#ifndef MSGQUEUE_HPP
#define MSGQUEUE_HPP

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define PATHNAME "/tmp"
const int PROJID = 0x123;

const int default_fd = -1;
const int default_size = 1024;

#define GET_MSGQUEUE (IPC_CREAT)
#define CREATE_MSGQUEUE (IPC_CREAT | IPC_EXCL | 0666)

class MsgQueue
{
    // 有类型数据块
    struct msgbuf {
        long mtype;
        char mtext[default_size];
    };
public:
    MsgQueue(int size = default_fd) {}

    void Create(int flag)
    {
        // 获取唯一键值
        key_t key = ::ftok(PATHNAME, PROJID);
        if(key < 0)
        {
            std::cerr << "ftok error" << std::endl;
            exit(1);
        }
        std::cout << "key: " << std::hex << key << std::endl;
        // 创建消息队列
        _msgfd = ::msgget(key, flag);
        if(_msgfd < 0)
        {
            std::cerr << "msgget error" << std::endl;
            exit(2);
        }
        std::cout << "msgqueue created: " << _msgfd << std::endl;
    }

    // 发送消息
    void Send(int type, const std::string &text)
    {
        struct msgbuf msg;
        memset(&msg, 0, sizeof(msg));
        msg.mtype = type;
        memcpy(msg.mtext, text.c_str(), text.size());
        // 问题：不能填写成为sizeof(msg)
        int n = msgsnd(_msgfd, &msg, sizeof(msg.mtext), 0);
        if(n < 0)
        {
            std::cerr << "msgsnd error" << std::endl;
            return ;
        }
    }

    // 接受消息
    void Recv(int type, std::string *text)
    {
        struct msgbuf msg;
        memset(&msg, 0, sizeof(msg));
        int n = msgrcv(_msgfd, &msg, sizeof(msg.mtext), type, 0);
        if(n < 0)
        {
            std::cerr << "msgrcv error" << std::endl;
            return ;
        }
        *text = msg.mtext;
    }

    // 获取消息队列中的属性
    void GetAttr()
    {
        struct msqid_ds outbuffer;
        int n = msgctl(_msgfd, IPC_STAT, &outbuffer);
        if(n < 0)
        {
            std::cerr << "msgctl error" << std::endl;
            return ;
        }
        std::cout << "outbuffer.msg_perm.__key: " << outbuffer.msg_perm.__key << std::endl;
    }

    void Destory()
    {
        int n = ::msgctl(_msgfd, IPC_RMID, nullptr);
        if(n == -1)
        {
            std::cerr << "msgctl error" << std::endl;
            return ;
        }
        std::cout << "msgctl success" << std::endl;
    }

    ~MsgQueue() {}

private:
    int _msgfd;
};

// 定义消息类型
#define MSG_TYPE_CLIENT 1
#define MSG_TYPE_SERVER 2

class Server : public MsgQueue
{
public:
    Server()
    {
        MsgQueue::Create(CREATE_MSGQUEUE);
        std::cout << "server create msgqueue done" << std::endl;
        MsgQueue::GetAttr();
    }

    ~Server()
    {
        MsgQueue::Destory();
    }
};

class Client : public MsgQueue
{
public:
    Client()
    {
        MsgQueue::Create(GET_MSGQUEUE);
        std::cout << "client get msgqueue done" << std::endl;
    }

    ~Client()
    {}
};

#endif  // MSGQUEUE_HPP